package com.hxrfid.project.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hxrfid.common.config.WeixinConfig;
import com.hxrfid.common.constant.BasicConstants;
import com.hxrfid.common.constant.UserConstants;
import com.hxrfid.common.core.domain.PageQuery;
import com.hxrfid.common.core.domain.entity.SysUser;
import com.hxrfid.common.core.page.TableDataInfo;
import com.hxrfid.common.enums.OrderStatusEnum;
import com.hxrfid.common.helper.LoginHelper;
import com.hxrfid.common.utils.StringUtils;
import com.hxrfid.common.utils.redis.RedisUtils;
import com.hxrfid.project.domain.BsDistributor;
import com.hxrfid.project.domain.BsOrder;
import com.hxrfid.project.domain.bo.BsDistributorBo;
import com.hxrfid.project.domain.bo.BsOrderBo;
import com.hxrfid.project.domain.vo.BsDistributorVo;
import com.hxrfid.project.domain.vo.BsOrderVo;
import com.hxrfid.project.mapper.BsDistributorMapper;
import com.hxrfid.project.service.IBsDistributorService;
import com.hxrfid.project.service.IBsOrderService;
import com.hxrfid.system.mapper.SysUserMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 分销员Service业务层处理
 *
 * @author hxrfid
 * @date 2025-07-30
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class BsDistributorServiceImpl extends ServiceImpl<BsDistributorMapper, BsDistributor> implements IBsDistributorService {

    private final BsDistributorMapper baseMapper;
    private final SysUserMapper sysUserMapper;
    private final IBsOrderService iBsOrderService;
    private final WeixinConfig weixinConfig;

    /**
     * 查询分销员
     *
     * @param id 主键ID
     * @return 分销员
     */
    @Override
    public BsDistributorVo queryById(Long id) {
        return baseMapper.selectVoById(id);
    }

    /**
     * 查询分销员列表
     *
     * @param bo        分销员对象
     * @param pageQuery 主键ID
     * @return 分销员列表
     */
    @Override
    public TableDataInfo<BsDistributorVo> queryPageList(BsDistributorBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<BsDistributor> lqw = buildQueryWrapper(bo);
        Page<BsDistributorVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        List<BsDistributorVo> records = result.getRecords();
        if (CollectionUtil.isNotEmpty(records)) {
            records.forEach(item -> {
                // 子用户数量
                List<SysUser> sysUsers = sysUserMapper.selectList(Wrappers.<SysUser>lambdaQuery().eq(SysUser::getParentId, item.getUserId()));
                // 订单数量
                if (CollectionUtil.isNotEmpty(sysUsers)) {
                    item.setChildCount(sysUsers.size());
                    List<Long> userIds = sysUsers.parallelStream().map(SysUser::getUserId).collect(Collectors.toList());
                    Long orderCount = iBsOrderService.lambdaQuery()
                        .in(BsOrder::getUserId, userIds)
                        .in(CollectionUtil.isNotEmpty(bo.getOrderStatusArr()), BsOrder::getOrderStatus, bo.getOrderStatusArr()).count();
                    item.setOrderCount(orderCount);
                } else {
                    item.setChildCount(BasicConstants.ZERO);
                    item.setOrderCount(BasicConstants.ZERO_LONG);
                }
                // 小程序二维码
                item.setWxCode(generateQrCode(item.getUserId()));
            });
        }
        return TableDataInfo.build(result);
    }

    /**
     * 查询分销员列表(小程序)
     * @param bo 分销员对象
     * @param pageQuery 主键ID
     * @return 分销员列表
     */
    @Override
    public TableDataInfo<SysUser> queryPageListChild(BsDistributorBo bo, PageQuery pageQuery) {
        QueryWrapper<SysUser> wrapper = Wrappers.query();
        wrapper.eq("u.del_flag", UserConstants.USER_NORMAL).eq("u.parent_id", LoginHelper.getUserId());
        Page<SysUser> page = sysUserMapper.selectPageUserList(pageQuery.build(), wrapper);
        List<SysUser> records = page.getRecords();
        if (CollectionUtil.isNotEmpty(records)) {
            records.forEach(user -> {
                // 订单数量
                Long orderCount = iBsOrderService.lambdaQuery().eq(BsOrder::getUserId, user.getUserId()).count();
                user.setOrderCount(orderCount);
            });
        }
        return TableDataInfo.build(page);
    }

    /**
     * 查询推广人订单列表(小程序)
     * @param bo 分销员对象
     * @param pageQuery 分页查询参数
     * @return 分销员订单列表
     */
    @Override
    public TableDataInfo<BsOrderVo> queryPageListOrder(BsDistributorBo bo, PageQuery pageQuery) {
        // 查询推广人
        QueryWrapper<SysUser> wrapper = Wrappers.query();
        wrapper.eq("parent_id", LoginHelper.getUserId());
        List<SysUser> sysUsers = sysUserMapper.selectList(wrapper);
        // 查询推广人订单
        List<Long> userIds = sysUsers.parallelStream().map(SysUser::getUserId).collect(Collectors.toList());
        BsOrderBo orderBo = new BsOrderBo();
        orderBo.setUserIds(userIds);
        orderBo.setOrderTimeArr(bo.getOrderTimeArr());
        return iBsOrderService.queryPageList(orderBo, pageQuery);
    }

    /**
     * 查询分销员订单统计信息
     * @return 分销员统计信息
     */
    @Override
    public Map<String, BigDecimal> queryCount() {
        Map<String, BigDecimal> map = new HashMap<>();
        // 查询推广人
        QueryWrapper<SysUser> wrapper = Wrappers.query();
        wrapper.eq("parent_id", LoginHelper.getUserId());
        List<SysUser> sysUsers = sysUserMapper.selectList(wrapper);
        // 查询推广人订单
        List<Long> userIds = sysUsers.parallelStream().map(SysUser::getUserId).collect(Collectors.toList());
        BsOrderBo orderBo = new BsOrderBo();
        orderBo.setUserIds(userIds);
        orderBo.setOrderStatusArr(Arrays.asList(OrderStatusEnum.TWO.getCode(), OrderStatusEnum.THREE.getCode(), OrderStatusEnum.FOUR.getCode()));
        List<BsOrderVo> bsOrderVos = iBsOrderService.queryList(orderBo);
        // 今日销售额
        BigDecimal todayAmount = bsOrderVos.stream().
            filter(item -> DateUtil.formatDate(DateUtil.date()).equals(DateUtil.format(item.getPayTime(), "yyyy-MM-dd")))
            .map(item -> NumberUtil.toBigDecimal(item.getRealPrice())).reduce(BigDecimal.ZERO, BigDecimal::add);
        map.put("todayAmount", todayAmount);
        // 月销售额
        BigDecimal monthAmount = bsOrderVos.stream().
            filter(item -> DateUtil.format(DateUtil.date(), "yyyy-MM").equals(DateUtil.format(item.getPayTime(), "yyyy-MM")))
            .map(item -> NumberUtil.toBigDecimal(item.getRealPrice())).reduce(BigDecimal.ZERO, BigDecimal::add);
        map.put("monthAmount", monthAmount);

        return map;
    }

    /**
     * 查询分销员列表
     *
     * @param bo 分销员对象
     * @return 分销员列表
     */
    @Override
    public List<BsDistributorVo> queryList(BsDistributorBo bo) {
        LambdaQueryWrapper<BsDistributor> lqw = buildQueryWrapper(bo);
        return baseMapper.selectVoList(lqw);
    }

    /**
     * 组装查询条件
     *
     * @param bo 分销员对象
     * @return 查询条件
     */
    private LambdaQueryWrapper<BsDistributor> buildQueryWrapper(BsDistributorBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<BsDistributor> lqw = Wrappers.lambdaQuery();
        lqw.eq(bo.getUserId() != null, BsDistributor::getUserId, bo.getUserId());
        lqw.like(StringUtils.isNotBlank(bo.getNickName()), BsDistributor::getNickName, bo.getNickName());
        lqw.eq(StringUtils.isNotBlank(bo.getAvatar()), BsDistributor::getAvatar, bo.getAvatar());
        lqw.eq(bo.getAreaId() != null, BsDistributor::getAreaId, bo.getAreaId());
        lqw.eq(StringUtils.isNotBlank(bo.getArea()), BsDistributor::getArea, bo.getArea());
        lqw.eq(StringUtils.isNotBlank(bo.getAreaAddr()), BsDistributor::getAreaAddr, bo.getAreaAddr());
        lqw.eq(bo.getRegisterTime() != null, BsDistributor::getRegisterTime, bo.getRegisterTime());
        lqw.eq(bo.getTenantId() != null, BsDistributor::getTenantId, bo.getTenantId());
        return lqw;
    }

    /**
     * 新增分销员
     *
     * @param bo 分销员对象
     * @return 是否成功
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public Boolean insertByBo(BsDistributorBo bo) {
        BsDistributor add = BeanUtil.toBean(bo, BsDistributor.class);
        validEntityBeforeSave(add);
        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            bo.setId(add.getId());
        }
        return flag;
    }

    /**
     * 修改分销员
     *
     * @param bo 分销员对象
     * @return 是否成功
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public Boolean updateByBo(BsDistributorBo bo) {
        BsDistributor update = BeanUtil.toBean(bo, BsDistributor.class);
        validEntityBeforeSave(update);
        return baseMapper.updateById(update) > 0;
    }

    /**
     * 保存前的数据校验
     *
     * @param entity 分销员对象
     */
    private void validEntityBeforeSave(BsDistributor entity) {
        //TODO 做一些数据校验,如唯一约束
    }

    /**
     * 批量删除分销员
     *
     * @param ids     主键ID的list
     * @param isValid 是否业务校验
     * @return 是否成功
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if (isValid) {
            //TODO 做一些业务上的校验,判断是否需要校验
        }
        return baseMapper.deleteBatchIds(ids) > 0;
    }

    /**
     * 获取微信访问令牌
     * @param accessToken
     */
    private String getAccessToken(String accessToken) {
        OkHttpClient client = new OkHttpClient();
        HttpUrl tokenHttpUrl = new HttpUrl.Builder()
            .scheme("https")
            .host("api.weixin.qq.com")
            .addPathSegment("cgi-bin")
            .addPathSegment("token")
            .addQueryParameter("grant_type", "client_credential")
            .addQueryParameter("appid", weixinConfig.getAppId())
            .addQueryParameter("secret", weixinConfig.getSecret())
            .build();
        Request request = new Request.Builder().url(tokenHttpUrl).build();
        try (Response response = client.newCall(request).execute()) {
            if (!response.isSuccessful()) {
                log.error("获取微信访问令牌失败，HTTP状态码: {}", response.code());
            }
            // 解析响应体
            JSONObject json = JSONUtil.parseObj(response.body().string());
            // 检查微信返回的错误码
            if (json.containsKey("errcode") && json.getInt("errcode") != 0) {
                String errorMsg = json.getStr("errmsg");
                log.error("获取微信访问令牌失败，微信错误码: {}，错误信息: {}", json.getInt("errcode"), errorMsg);
            }
            accessToken = json.getStr("access_token");
            if (StringUtils.isEmpty(accessToken)) {
                log.error("微信返回的访问令牌为空");
            }
        } catch (IOException e) {
            log.error("获取微信访问令牌时发生IO异常", e);
        }
        return accessToken;
    }

    /**
     * 生成小程序二维码
     */
    private String generateQrCode(Long userId) {
        try {
            // 获取访问令牌
            String accessToken = getValidAccessToken();
            if (StringUtils.isEmpty(accessToken)) {
                log.error("无法获取有效的微信访问令牌");
                return "";
            }

            // 构建请求体
            JSONObject requestBody = buildQrCodeRequestBody(userId);

            // 执行请求
            byte[] qrCodeData = executeQrCodeRequest(accessToken, requestBody);
            if (qrCodeData != null && qrCodeData.length > 0) {
                return Base64.getEncoder().encodeToString(qrCodeData);
            }
        } catch (Exception e) {
            log.error("生成微信二维码时发生异常，userId: {}", userId, e);
        }
        return "";
    }

    /**
     * 获取有效的访问令牌
     */
    private String getValidAccessToken() {
        String accessToken = RedisUtils.getCacheObject("weixin:access_token");
        if (StringUtils.isEmpty(accessToken)) {
            accessToken = getAccessToken(accessToken);
            if (StringUtils.isNotEmpty(accessToken)) {
                // 设置缓存，提前5分钟过期
                RedisUtils.setCacheObject("weixin:access_token", accessToken, Duration.ofSeconds(7000));
            }
        }
        return accessToken;
    }

    /**
     * 构建小程序码请求体
     */
    private JSONObject buildQrCodeRequestBody(Long userId) {
        JSONObject requestBody = new JSONObject();
        // 场景值，用于传递参数
        requestBody.put("scene", "parentId=" + userId);
        // 使用正确的页面路径
        requestBody.put("page", "pages/mine/mine");
        // 可选参数
        requestBody.put("width", 430); // 二维码宽度
        requestBody.put("auto_color", false); // 是否自动配置线条颜色
        requestBody.put("line_color", new JSONObject().put("r", 0).put("g", 0).put("b", 0)); // 二维码颜色
        requestBody.put("is_hyaline", false); // 是否需要透明底色

        // 添加调试日志
        log.info("构建小程序码请求体，userId: {}, page: pages/mine/mine, scene: parentId={}", userId, userId);

        return requestBody;
    }

    /**
     * 执行小程序码请求
     */
    private byte[] executeQrCodeRequest(String accessToken, JSONObject requestBody) {
        OkHttpClient client = new OkHttpClient.Builder()
            .connectTimeout(10, TimeUnit.SECONDS)
            .readTimeout(30, TimeUnit.SECONDS)
            .writeTimeout(30, TimeUnit.SECONDS)
            .build();

        MediaType mediaType = MediaType.parse("application/json; charset=utf-8");
        RequestBody body = RequestBody.create(mediaType, requestBody.toString());

        Request request = new Request.Builder()
            .url("https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=" + accessToken)
            .post(body)
            .build();

        try (Response response = client.newCall(request).execute()) {
            if (!response.isSuccessful()) {
                String errorMsg = response.body() != null ? response.body().string() : "无错误信息";
                log.error("生成小程序码请求失败，状态码: {}, 错误信息: {}", response.code(), errorMsg);
                return null;
            }

            ResponseBody responseBody = response.body();
            if (responseBody == null) {
                log.error("生成小程序码响应体为空");
                return null;
            }

            byte[] data = responseBody.bytes();

            // 检查是否是图片数据
            if (isImageData(data)) {
                log.info("成功生成小程序码，数据大小: {} bytes", data.length);
                return data;
            } else {
                // 解析错误信息 - 尝试多种编码格式
                String errorStr = new String(data, StandardCharsets.UTF_8);
                log.error("生成小程序码失败, 错误信息: {}", errorStr);

                // 尝试解析JSON错误信息
                try {
                    // 检查是否是有效的JSON格式
                    if (errorStr.trim().startsWith("{") && errorStr.trim().endsWith("}")) {
                        JSONObject errorJson = JSONUtil.parseObj(errorStr);
                        int errCode = errorJson.getInt("errcode", -1);
                        String errMsg = errorJson.getStr("errmsg", "未知错误");

                        switch (errCode) {
                            case 41030:
                                log.error("页面路径错误，请检查page参数是否正确: {}", errMsg);
                                break;
                            case 40001:
                                log.error("获取access_token时AppSecret错误，或者access_token无效: {}", errMsg);
                                break;
                            case 40013:
                                log.error("不合法的AppID: {}", errMsg);
                                break;
                            case 41008:
                                log.error("缺少scene参数: {}", errMsg);
                                break;
                            default:
                                log.error("微信API错误，错误码: {}, 错误信息: {}", errCode, errMsg);
                        }
                    } else {
                        log.error("返回的数据不是有效的JSON格式，可能是图片数据: {}", errorStr.substring(0, Math.min(100, errorStr.length())));
                    }
                } catch (Exception e) {
                    log.error("解析错误信息失败，原始数据: {}", errorStr.substring(0, Math.min(100, errorStr.length())), e);
                }
                return null;
            }
        } catch (IOException e) {
            log.error("请求微信API时发生IO异常", e);
            return null;
        }
    }

    /**
     * 判断返回数据是否为图片数据
     * 支持PNG、JPEG、GIF等常见图片格式
     */
    private boolean isImageData(byte[] data) {
        if (data.length < 4) {
            return false;
        }

        // PNG图片文件头: 89 50 4E 47
        if (data[0] == (byte) 0x89 && data[1] == (byte) 0x50 &&
            data[2] == (byte) 0x4E && data[3] == (byte) 0x47) {
            return true;
        }

        // JPEG图片文件头: FF D8 FF
        if (data[0] == (byte) 0xFF && data[1] == (byte) 0xD8 &&
            data[2] == (byte) 0xFF) {
            return true;
        }

        // GIF图片文件头: 47 49 46 38 (GIF87a) 或 47 49 46 38 39 (GIF89a)
        if (data[0] == (byte) 0x47 && data[1] == (byte) 0x49 &&
            data[2] == (byte) 0x46 && data[3] == (byte) 0x38) {
            return true;
        }

        // 检查是否包含常见的图片二进制特征
        // 如果数据中包含大量非ASCII字符，可能是图片数据
        int nonAsciiCount = 0;
        for (int i = 0; i < Math.min(data.length, 100); i++) {
            if (data[i] < 32 || data[i] > 126) {
                nonAsciiCount++;
            }
        }

        // 如果超过80%的字符都是非ASCII，可能是图片数据
        return (double) nonAsciiCount / Math.min(data.length, 100) > 0.8;
    }
}
